home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / POPCLI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-07  |  10.5 KB  |  446 lines

  1. /*
  2.  *    POP2 Client routines.  Originally authored by Mike Stockett
  3.  *      (WA7DYX).
  4.  *    Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
  5.  *    facilities in NOS0423.  Fixed type mismatches spotted by C++.
  6.  *    Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  7.  *      with later releases (NOS0522).
  8.  *    Added into NOS by PA0GRI (and linted into "standard" C)
  9.  *
  10.  *    Some code culled from previous releases of SMTP.
  11.  *
  12.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  13.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  14.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  15.  *    Permission granted for non-commercial copying and use, provided
  16.  *      this notice is retained.
  17.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  18.  *      also rebuilt locking mechanism
  19.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  20.  *    Permission granted for non-commercial copying and use, provided
  21.  *    this notice is retained.
  22.  */
  23. #include "global.h"
  24. #ifdef POP
  25. #ifndef MSDOS
  26. #include <setjmp.h>
  27. #include <stdarg.h>
  28. #include "mbuf.h"
  29. #include "proc.h"
  30. #include "socket.h"
  31. #endif
  32. #include "hardware.h"
  33. #include "cmdparse.h"
  34. #include "netuser.h"
  35. #include "files.h"
  36. #include "mailutil.h"
  37.  
  38. #if !defined(_lint)
  39. static char rcsid[] OPTIONAL = "$Id: popcli.c,v 1.17 1997/09/07 21:18:28 root Exp root $";
  40. #endif
  41.  
  42. #define BUF_LEN        257
  43.  
  44. /* POP client control block */
  45.  
  46. struct pop_ccb {
  47.     int socket;        /* socket for this connection */
  48.     char state;        /* client state */
  49. #define       CALL        0
  50. #define       NMBR        3
  51. #define       SIZE        5
  52. #define       XFER        8
  53. #define       EXIT        10
  54.     char buf[BUF_LEN];    /* tcp input buffer */
  55.     int folder_len;        /* number of msgs in current folder */
  56.     long msg_len;        /* length of current msg */
  57.     int msg_num;        /* current message number */
  58. };
  59. static struct pop_ccb *ccb;
  60.  
  61. #define NULLCCB        (struct pop_ccb *)0
  62.  
  63. static int Popquiet = 0;
  64.  
  65. static struct timer popcli_t;
  66. static uint32 mailhost;
  67. static char mailbox_name[10], mailbox_pathname[BUF_LEN], username[20],
  68.      password[20], Workfile_name[] = "mbox.pop";
  69.  
  70. static int domailbox (int argc, char *argv[], void *p);
  71. static int domailhost (int argc, char *argv[], void *p);
  72. static int douserdata (int argc, char *argv[], void *p);
  73. static int doquiet (int argc, char *argv[], void *p);
  74. static int dotimer (int argc, char *argv[], void *p);
  75. static struct pop_ccb *new_ccb (void);
  76. static void delete_ccb (void);
  77. static void pop_send (int unused, void *cb1, void *p);
  78. static int popkick (int argc, char *argv[], void *p);
  79. int dopop (int argc, char *argv[], void *p);
  80. static void pop_csm (struct pop_ccb * theccb);
  81. static void quit_session (struct pop_ccb * theccb);
  82. extern void rrip (register char *s);
  83.  
  84. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  85. static int poptick (void);
  86.  
  87. static struct cmds Popcmds[] =
  88. {
  89.     { "mailbox",    domailbox,    0, 0, NULLCHAR },
  90.     { "mailhost",    domailhost,    0, 0, NULLCHAR },
  91.     { "kick",    popkick,    0, 0, NULLCHAR },
  92.     { "quiet",    doquiet,    0, 0, NULLCHAR },
  93.     { "timer",    dotimer,    0, 0, NULLCHAR },
  94.     { "userdata",    douserdata,    0, 0, NULLCHAR },
  95.     { NULLCHAR,    0,        0, 0, NULLCHAR }
  96. };
  97.  
  98.  
  99. /* Command string specifications */
  100.  
  101. static char ackd_cmd[] = "ACKD\n";
  102. static char login_cmd[] = "HELO %s %s\n";
  103. static char quit_cmd[] = "QUIT\n";
  104. static char read_cur_cmd[] = "READ\n";
  105. static char retr_cmd[] = "RETR\n";
  106. static const char *greeting_rsp = "+ POP2 ";
  107.  
  108. #ifdef POP_FOLDERS
  109. static char fold_cmd[] = "FOLD %s\n";
  110. #endif
  111. #if 0
  112. static char nack_cmd[] = "NACK\n";    /* Not implemented */
  113. #endif
  114.  
  115.  
  116. static FILE *fd;
  117.  
  118.  
  119.  
  120. int
  121. dopop (int argc, char *argv[], void *p)
  122. {
  123.     return subcmd (Popcmds, argc, argv, p);
  124. }
  125.  
  126.  
  127.  
  128. static int
  129. domailbox (int argc, char *argv[], void *p OPTIONAL)
  130. {
  131.     if (argc < 2) {
  132.         if (mailbox_name[0] == '\0')
  133.             tputs ("mailbox name not set yet\n");
  134.         else
  135.             tprintf ("%s\n", mailbox_name);
  136.     } else
  137.         strncpy (mailbox_name, argv[1], 10);
  138.  
  139.     return 0;
  140. }
  141.  
  142.  
  143.  
  144. static int
  145. domailhost (int argc, char *argv[], void *p OPTIONAL)
  146. {
  147. uint32 n;
  148.  
  149.     if (argc < 2)
  150.         tprintf ("%s\n", inet_ntoa (mailhost));
  151.     else if ((n = resolve (argv[1])) == 0) {
  152.         tprintf (Badhost, argv[1]);
  153.         return 1;
  154.     } else
  155.         mailhost = n;
  156.  
  157.     return 0;
  158. }
  159.  
  160.  
  161.  
  162. static int
  163. doquiet (int argc, char *argv[], void *p OPTIONAL)
  164. {
  165.     return setbool (&Popquiet, "POP quiet", argc, argv);
  166. }
  167.  
  168.  
  169.  
  170. static int
  171. douserdata (int argc, char *argv[], void *p OPTIONAL)
  172. {
  173.     if (argc < 2)
  174.         tprintf ("%s\n", username);
  175.     else if (argc != 3) {
  176.         tputs ("Usage: pop userdata <username> <password>\n");
  177.         return 1;
  178.     } else {
  179.         sscanf (argv[1], "%18s", username);
  180.         sscanf (argv[2], "%18s", password);
  181.     }
  182.  
  183.     return 0;
  184. }
  185.  
  186.  
  187.  
  188. /* Set scan interval */
  189.  
  190. static int
  191. dotimer (int argc, char *argv[], void *p OPTIONAL)
  192. {
  193.     if (argc < 2) {
  194.         tprintf ("%lu/%lu\n", read_timer (&popcli_t) / 1000L, dur_timer (&popcli_t) / 1000L);
  195.         return 0;
  196.     }
  197.     popcli_t.func = (void (*)(void *)) poptick;    /* what to call on timeout */
  198.     popcli_t.arg = NULL;    /* dummy value */
  199.     set_timer (&popcli_t, atol (argv[1]) * 1000L);    /* set timer duration */
  200.     start_detached_timer (&popcli_t);/* and fire it up */
  201.     return 0;
  202. }
  203.  
  204.  
  205.  
  206. static int
  207. popkick (int argc OPTIONAL, char *argv[]OPTIONAL, void *p OPTIONAL)
  208. {
  209.     (void) poptick ();
  210.     return 0;
  211. }
  212.  
  213.  
  214.  
  215. static int
  216. poptick ()
  217. {
  218.     if (ccb == NULLCCB) {
  219.         /* Don't start if any of the required parameters have not been specified */
  220.  
  221.         if (mailhost == 0) {
  222.             tputs ("mailhost not defined yet.(pop mailhost <host>)\n");
  223.             return 0;
  224.         }
  225.         if (mailbox_name[0] == '\0') {
  226.             tputs ("mailbox name not defined yet.(pop mailbox <name>)\n");
  227.             return 0;
  228.         }
  229.         if (username[0] == '\0') {
  230.             tputs ("username not defined yet. (pop user <name> <pass>)\n");
  231.             return 0;
  232.         }
  233.         if (password[0] == '\0') {
  234.             tputs (" Unknown password\n");
  235.             return 0;
  236.         }
  237.         if ((ccb = new_ccb ()) == NULLCCB) {
  238.             tcmdprintf ("*** Unable to allocate CCB\n");
  239.             return 0;
  240.         }
  241.         (void) newproc ("Auto-POP Client", 1024, pop_send, 0, ccb, NULL, 0);
  242.     }
  243.     /* Restart timer */
  244.  
  245.     start_detached_timer (&popcli_t);
  246.     return 0;
  247. }
  248.  
  249.  
  250.  
  251. /* this is the master state machine that handles a single SMTP transaction */
  252. /* it is called with a queue of jobs for a particular host. */
  253.  
  254. static void
  255. pop_send (int unused OPTIONAL, void *cb1, void *p OPTIONAL)
  256. {
  257. char const *cp;
  258. struct sockaddr_in fsocket;
  259. struct pop_ccb *theccb;
  260.  
  261.     theccb = (struct pop_ccb *) cb1;
  262.     fsocket.sin_family = AF_INET;
  263.     fsocket.sin_addr.s_addr = mailhost;
  264.     fsocket.sin_port = IPPORT_POP;
  265.  
  266.     theccb->socket = socket (AF_INET, SOCK_STREAM, 0);
  267.  
  268.     theccb->state = CALL;
  269.  
  270.     if (connect (theccb->socket, (char *) &fsocket, SOCKSIZE) == 0)
  271.         log (theccb->socket, "Connected to mailhost %s", inet_ntoa (mailhost));
  272.     else {
  273.         cp = sockerr (theccb->socket);
  274.         log (theccb->socket, "Connect to mailhost %s failed: %s", inet_ntoa (mailhost),
  275.              (cp != NULLCHAR) ? cp : "");
  276.     }
  277.  
  278.     for (;;) {
  279.         if (recvline (theccb->socket, (unsigned char *) theccb->buf, BUF_LEN) == -1)
  280.             break;
  281.  
  282.         rrip (theccb->buf);
  283.         pop_csm (theccb);
  284.         if (theccb->state == EXIT)
  285.             break;
  286.     }
  287.  
  288.     log (theccb->socket, "Connection closed to mailhost %s", inet_ntoa (mailhost));
  289.     close_s (theccb->socket);
  290.     if (fd != NULLFILE)
  291.         fclose (fd);
  292.     delete_ccb ();
  293. }
  294.  
  295.  
  296.  
  297. /* free the message struct and data */
  298.  
  299. static void
  300. delete_ccb ()
  301. {
  302.     if (ccb == NULLCCB)
  303.         return;
  304.  
  305.     free ((char *) ccb);
  306.     ccb = NULLCCB;
  307. }
  308.  
  309.  
  310.  
  311. /* create a new  pop control block */
  312.  
  313. static struct pop_ccb *
  314. new_ccb ()
  315. {
  316. register struct pop_ccb *theccb;
  317.  
  318.     if ((theccb = (struct pop_ccb *) callocw (1, sizeof (struct pop_ccb))) == NULLCCB)
  319.                 return (NULLCCB);
  320.  
  321.     return (theccb);
  322. }
  323.  
  324.  
  325.  
  326. /* ---------------------- pop client code starts here --------------------- */
  327.  
  328. static void
  329. pop_csm (struct pop_ccb *theccb)
  330. {
  331. FILE *mf;
  332.  
  333.     switch (theccb->state) {
  334.         case CALL:
  335.             if (strncmp (theccb->buf, greeting_rsp, strlen (greeting_rsp)) == 0) {
  336.                 (void) usprintf (theccb->socket, login_cmd, username, password);
  337.                 theccb->state = NMBR;
  338.             } else
  339.                 quit_session (theccb);
  340.             break;
  341.  
  342.         case NMBR:
  343.             switch (theccb->buf[0]) {
  344.                 case '#':
  345.                     if ((fd = fopen (Workfile_name, "a+")) == NULLFILE) {
  346.                         perror ("Unable to open work file");
  347.                         quit_session (theccb);
  348.                         return;
  349.                     }
  350.                     fseek (fd, 0, SEEK_SET);
  351.                     theccb->folder_len = atoi (&(theccb->buf[1]));
  352.                     (void) usprintf (theccb->socket, read_cur_cmd);
  353.                     theccb->state = SIZE;
  354.                     break;
  355.  
  356.                 case '+':
  357.  
  358.                     /* If there is no mail (the only time we get a "+"
  359.                      * response back at this stage of the game),
  360.                      * then just close out the connection, because
  361.                      * there is nothing more to do!! */
  362.  
  363.                 default:
  364.                     quit_session (theccb);
  365.                     break;
  366.             }
  367.             break;
  368.  
  369.         case SIZE:
  370.             if (theccb->buf[0] == '=') {
  371.                 theccb->msg_len = atol (&(theccb->buf[1]));
  372.                 if (theccb->msg_len > 0) {
  373.                     (void) usprintf (theccb->socket, retr_cmd);
  374.                     theccb->state = XFER;
  375.                 } else {
  376.                     log (theccb->socket, "POP client retrieved %d messages",
  377.                          theccb->folder_len);
  378.  
  379.                     /* All done, so do local cleanup */
  380.  
  381.                     if (mlock (Mailspool, mailbox_name)) {
  382.                         tprintf ("\n*** Local mailbox locked, new mail in file %s\n", Workfile_name);
  383.                         quit_session (theccb);
  384.                         return;
  385.                     }
  386.                     sprintf (mailbox_pathname, "%s/%s.txt", Mailspool, mailbox_name);
  387.                     if ((mf = fopen (mailbox_pathname, "a+")) == NULL) {
  388.                         tprintf ("\n*** Unable to open local mailbox, new mail in file %s\n", Workfile_name);
  389.                         quit_session (theccb);
  390.                         return;
  391.                     }
  392.                     fseek (fd, 0, SEEK_SET);
  393.  
  394.                     while (!feof (fd)) {
  395.                         if (fgets (theccb->buf, BUF_LEN, fd) != NULLCHAR)
  396.                             fputs (theccb->buf, mf);
  397.                     }
  398.                     fclose (mf);
  399.                     fclose (fd);
  400.                     fd = NULL;
  401.                     tprintf ("New mail arrived for %s from mailhost <%s>%c\n",
  402.                          mailbox_name, inet_ntoa (mailhost), Popquiet ? ' ' : '\007');
  403.                     rmlock (Mailspool, mailbox_name);
  404.                     unlink (Workfile_name);
  405.                     quit_session (theccb);
  406.                 }
  407.             } else
  408.                 quit_session (theccb);
  409.             break;
  410.  
  411.         case XFER:
  412.             fprintf (fd, "%s\n", theccb->buf);
  413.  
  414.             theccb->msg_len -= (long) (strlen (theccb->buf) + 2);    /* Add CRLF */
  415.  
  416.             if (theccb->msg_len > 0)
  417.                 return;
  418.  
  419.             (void) usprintf (theccb->socket, ackd_cmd);
  420.  
  421.             theccb->msg_num++;
  422.             theccb->state = SIZE;
  423.             break;
  424.  
  425.         case EXIT:
  426.             if (fd != NULLFILE)
  427.                 fclose (fd);
  428.             break;
  429.  
  430.         default:
  431.             break;
  432.     }
  433. }
  434.  
  435.  
  436.  
  437. static void
  438. quit_session (struct pop_ccb *theccb)
  439. {
  440.     (void) usprintf (theccb->socket, quit_cmd);
  441.  
  442.     theccb->state = EXIT;
  443. }
  444.  
  445. #endif /* POP */
  446.